/**
**********************************************************************************************************************************************************************************************************************************
* @file:	File.h
* @author:	zinface
* @date:	2021年09月20日 22:26:39 星期一
* @brief:	FinalC 提供的的 File 数据类型操作
**********************************************************************************************************************************************************************************************************************************
**/

#include "FinalCType/File.h"

// FinalC_Object_Define(File) {
//     long size;
//     bool exists;
//     String *path;
//     FilePermissions *perm;
// };
FinalC_Object_Size(File);

// #define FinalC_File_Func_Define(func) \
//         FinalC_Object_Func_Suffix(file, func)

// ------------------------------------ file utils
// bool fileExists(File *f) {
//     struct stat s = {0};
//     errno = 0;
//     if (stat((const char *)f->path->value, &s) != 0) {
//         // printf("错误信息： %s - %d\n",strerror(errno), errno);
//         switch (errno) {
//             case ENOENT: f->exists = false;
//         }
//     } else {
//         f->exists = true;
//     }
//     return f->exists;
// }

// bool fileSize(File *f) {

// }

// static char FCT[][10] = {"r", "w", "rw"};

// typedef enum FILE_CTL_TYPE fileCtlType;
// enum FILE_CTL_TYPE {
//     RO = 0,
//     WO = 1,
//     RW = 2,
// };

void FinalC_File_Func_Define(LoadInfo)(File *f) {
// void fileLoadInfo(File *f) {
    errno = 0;
    if (f->path && f->path->value) {
        filePermissionSetWith_cstr(f->perm, f->path->value);
        if (!S_ISDIR(f->perm->st.st_mode)) {
            f->size = f->perm->st.st_size;
            f->exists = true;
        }
    }
}

// ------------------------------------ Constructor
/**
 * createFile: 创建空的 File 对象实例
 *
 */
FINALC_WARN_UNUSED_RESULT
FinalC_Object_Create_Define(File) {
    File *f = (File*)calloc(FileSize(), 1);
    f->path = createString();
    f->perm = createFilePermissions();
    f->size = 0;
    f->exists = false;
    return f;
}

FINALC_WARN_UNUSED_RESULT
FinalC_Object_Create_With_Obj_Define(File, String) {
    File *f = createFile();
    if (v && v->value && v->len) {
        stringAppend_cstr(f->path, v->value);
        fileLoadInfo(f);
    }
    return f;
}

FINALC_WARN_UNUSED_RESULT
FinalC_Object_Create_With_Obj_After_Define(File, String, delete) {
    File *f = createFileWithString(v);
    if (after == deleteString || after == destroyString)
        after(v);

    fileLoadInfo(f);
    return f;
}

/**
 * createFileWith_cstr: 基于给定的字符创建 File 对象实例
 * 
 */

FINALC_WARN_UNUSED_RESULT
File *createFileWith_cstr(char *str) {
    File *f = createFileWithStringAfter(createStringWith_cstr(str), destroyString);
    fileLoadInfo(f);
    return f;
}

// ------------------------------------ Destructor
/**
 * destroyFile: 释放 File 对象
 *
 * NOTE: 该对象指向的元素(如有)将不会进行释放，否则使用 deleteFile()
 */
FinalC_Object_Destroy_Define(File) {
    if (v && v->path) v->path = NULL;
    if (v && v->perm) v->perm = NULL;
    if (v) free(v);
    if (v) v = NULL;
}

/**
 * deleteFile: 销毁 File 对象
 *
 * NOTE: 该对象指向的内存(如有)将会进行释放
 */
FinalC_Object_Delete_Define(File) {
    if (v && v->path) deleteString(v->path);
    if (v && v->perm) deleteFilePermissions(v->perm);
    destroyFile(v);
}


// ------------------------------------ File Open
// void fileRead(FILE *fp) {

// }

FILE *FinalC_File_Func_Define(Open)(File *f, fileCtlType type) {
    return fopen(f->path->value, FCT[type]);
}

// ------------------------------------ ReadToString
FINALC_WARN_UNUSED_RESULT
String *FinalC_File_Func_Define(ReadToString)(File *f) {
    FILE *fp = NULL;

    String *s = createStringWith_size(f->size);

    if (f && f->exists && ((fp = fileOpen(f, RO)) != NULL)) {
        fread(s->value, 1, s->len, fp);
        fclose(fp);
    } else {
        clearString(s);
    }
    return s;
}

// ------------------------------------ Write With String

void FinalC_File_Func_Define(WriteWithString)(File *f, String *s) {
    FILE *fp = NULL;

    if (f && f->exists && ((fp = fileOpen(f, WO)) != NULL)) {
        fwrite(s->value, 1, s->len, fp);
        fclose(fp);
    }
}